/* Title:		
 *
 * Project:     MAS
 *
 * @ Link: 		http://...
 *
 * @ Email:		ivan_ling@hotmail.com
 *
 * @ Copyright: Copyright (c) 2008 mezimedia
 *
 * @ Author 	Ivan.ling
 *
 * @ Version 	1.0
 
 * @ last change time 2008-01-20 	
 */
package com.pub.util;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class SecurityUtils
{
	public static final String STR_DES_ALGORITHM 	= "DES"; 
	public static final String STR_DES_ALGORITHM_3 	= "DESede/CBC/PKCS5Padding"; 

	//private static String STR_IV 	= "$h$%^0@~";
	private static String StrDefaultKeyDES = "c$9D2@y~";
	private static String StrDefaultKeyDES3 = "1mk32oo3c3)(~3/.+=04#b0&";
	
	private static Random randGen = null;
	private static char[] numbersAndLetters = null;
	private static Object initLock = new Object();
	
	private String iv;
	
	public SecurityUtils()
	{
	}
	
	@SuppressWarnings("static-access")
	public static void main(String args[])
	{
		SecurityUtils su = new SecurityUtils();
		try {
			//String strKey = "123456789012345678901234";
			//String strKeyDES = "c$9D2@y~";
			
			System.out.println("====******2222222222222========= = " + su.strEncryptByDES("12345678", StrDefaultKeyDES));
			
//			String strEN = su.strEncryptByIVDES3("5105105105105100", StrDefaultKeyDES3);
//			
//			System.out.println("====****** encrypt word ========= = " + strEN);
//			System.out.println("=====****** decrypt====== = " + su.strDecryptByIVDES3(su.getIV(), strEN, StrDefaultKeyDES3));
//		
//			
//			strEN = su.strEncryptByDES("5105105105105100");
//			System.out.println("====-------- des encrypt word ========= = " + strEN);
//			
//			strEN = "EUOoB7EYDuF7T/Ap8i+zZ/Aqgr57FbBT";
//			System.out.println("=====________des decrypt====== = " + su.strDecryptByDES(strEN));
//			
//			System.out.println("MD5 = " + su.strMD5("111"));
//			
//			System.out.println("strGetRandom = " + su.randomString(8));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static long strGetRandom(int iLength)
	{
		int iLimit = 1;
		for(int i = 0; i < iLength; i++)
			iLimit = iLimit * 10;
		
		return Math.round(Math.random() * iLimit);
	}
	
	/**
	 * ECB module and NoPadding fill DES encrypt method.
	 * @param src 			# encrypt string
	 * @param sKeyByte 		# encrypt key
	 * @return encryptByte 	# cryptograph
	 */
	public static String strEncryptByDES(String strSrc, String strKeyByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
	{
	    Cipher myCipher = Cipher.getInstance(STR_DES_ALGORITHM);
	    SecretKey sKey = new SecretKeySpec(strKeyByte.getBytes(), "DES");
	    myCipher.init(Cipher.ENCRYPT_MODE, sKey);
	    
		return Base64.encode(myCipher.doFinal(strSrc.getBytes()));
	}

	/**
	 * ECB module and NoPadding fill DES encrypt method.
	 * @param src 			# encrypt string
	 * @param sKeyByte 		# encrypt key
	 * @return encryptByte 	# cryptograph
	 */
	public static String strEncryptByDES(String strSrc) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
	{
	    Cipher myCipher = Cipher.getInstance(STR_DES_ALGORITHM);
	    SecretKey sKey = new SecretKeySpec(SecurityUtils.StrDefaultKeyDES.getBytes(), "DES");
	    myCipher.init(Cipher.ENCRYPT_MODE, sKey);
	    
		return Base64.encode(myCipher.doFinal(strSrc.getBytes()));
	}

	/**
	 * DES decrypt method.
	 * @param src 			# cryptograph
	 * @param sKeyByte 		# encrypt key
	 * @return decryptByte 	# password
	 * @throws NoSuchPaddingException 
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeyException 
	 * @throws BadPaddingException 
	 * @throws IllegalBlockSizeException 
	 * @throws IOException 
	 */
	public static String strDecryptByDES(String strSrc, String strKeyByte) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException
	{
        Cipher myCipher = Cipher.getInstance(STR_DES_ALGORITHM);
        SecretKey sKey = new SecretKeySpec(strKeyByte.getBytes(), "DES");
        myCipher.init(Cipher.DECRYPT_MODE, sKey);
  
  		return new String(myCipher.doFinal(Base64.decode(strSrc.getBytes())));
	}

	/**
	 * DES decrypt method.
	 * @param src 			# cryptograph
	 * @param sKeyByte 		# encrypt key
	 * @return decryptByte 	# password
	 * @throws NoSuchPaddingException 
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeyException 
	 * @throws BadPaddingException 
	 * @throws IllegalBlockSizeException 
	 * @throws IOException 
	 */
	public static String strDecryptByDES(String strSrc) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException
	{
        Cipher myCipher = Cipher.getInstance(STR_DES_ALGORITHM);
        SecretKey sKey = new SecretKeySpec(SecurityUtils.StrDefaultKeyDES.getBytes(), "DES");
        myCipher.init(Cipher.DECRYPT_MODE, sKey);
  
  		return new String(myCipher.doFinal(Base64.decode(strSrc.getBytes())));
	}
	
	public static String strEncrypt(String strAlgorithm, String strIV, String strSource, String strKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(strKey.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(strIV.getBytes());
		Cipher cipher = Cipher.getInstance(strAlgorithm);
		cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
		
		return Base64.encode(cipher.doFinal(strSource.getBytes()));
	}

	public static String strEncryptByDES3(String strIV, String strSource) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(SecurityUtils.StrDefaultKeyDES3.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(strIV.getBytes());
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
		
		return Base64.encode(cipher.doFinal(strSource.getBytes()));
	}

	public static String strEncryptByDES3(String strIV, String strSource, String strKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(strKey.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(strIV.getBytes());
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
		
		return Base64.encode(cipher.doFinal(strSource.getBytes()));
	}

	public String getIV()
	{
		return iv;
	}
	
	public String strEncryptByIVDES3(String strSource, String strKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
	{
		StringBuilder sbCache = new StringBuilder(30);
		if(strKey.length() > 16)
			sbCache.append(strKey.substring(0, 16));
		else
			sbCache.append(strKey);
		
		this.iv = randomString(8);
		sbCache.append(this.iv);
		
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(sbCache.toString().getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(this.iv.getBytes());
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
		
		return Base64.encode(cipher.doFinal(strSource.getBytes()));
	}

	public String strDecryptByIVDES3(String strIV, String strSource, String strKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException
	{
		StringBuilder sbCache = new StringBuilder(30);
		if(strKey.length() > 16)
			sbCache.append(strKey.substring(0, 16));
		else
			sbCache.append(strKey);
		sbCache.append(strIV);
		
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(sbCache.toString().getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(strIV.getBytes());
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.DECRYPT_MODE, securekey, iv, sr);
		
		return new String(cipher.doFinal(Base64.decode(strSource.getBytes())));
	}

	public static String strEncryptByDES3(byte[] btIV, byte[] btSource) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(SecurityUtils.StrDefaultKeyDES3.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(btIV);
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
		
		return Base64.encode(cipher.doFinal(btSource));
	}
	
	public static String strEncryptByDES3(byte[] btIV, byte[] btSource, byte[] btKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(btKey);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(btIV);
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.ENCRYPT_MODE, securekey, iv, sr);
		
		return Base64.encode(cipher.doFinal(btSource));
	}

	public static String strDecrypt(String strAlgorithm, String strIV, String strSource, String strKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(strKey.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(strIV.getBytes());
		Cipher cipher = Cipher.getInstance(strAlgorithm);
		cipher.init(Cipher.DECRYPT_MODE, securekey, iv, sr);
		
		return new String(cipher.doFinal(Base64.decode(strSource.getBytes())));
	}
	
	public static String strDecryptByDES3(String strIV, String strSource) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(SecurityUtils.StrDefaultKeyDES3.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(strIV.getBytes());
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.DECRYPT_MODE, securekey, iv, sr);
		
		return new String(cipher.doFinal(Base64.decode(strSource.getBytes())));
	}
	
	public static String strDecryptByDES3(String strIV, String strSource, String strKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(strKey.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(strIV.getBytes());
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.DECRYPT_MODE, securekey, iv, sr);
		
		return new String(cipher.doFinal(Base64.decode(strSource.getBytes())));
	}

	public static String strDecryptByDES3(byte[] btIV, byte[] btSource) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(SecurityUtils.StrDefaultKeyDES3.getBytes());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(btIV);
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.DECRYPT_MODE, securekey, iv, sr);
		
		return new String(cipher.doFinal(Base64.decode(btSource)));
	}
	
	public static String strDecryptByDES3(byte[] btIV, byte[] btSource, byte[] btKey) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException
	{
		SecureRandom sr = new SecureRandom();
		DESedeKeySpec dks = new DESedeKeySpec(btKey);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		SecretKey securekey = keyFactory.generateSecret(dks);
		IvParameterSpec iv = new IvParameterSpec(btIV);
		Cipher cipher = Cipher.getInstance(SecurityUtils.STR_DES_ALGORITHM_3);
		cipher.init(Cipher.DECRYPT_MODE, securekey, iv, sr);
		
		return new String(cipher.doFinal(Base64.decode(btSource)));
	}

	public static String getMD5(String strSource) throws NoSuchAlgorithmException 
	{
	    MessageDigest md = MessageDigest.getInstance("MD5");
	    
	    return dumpBytes(md.digest(strSource.getBytes()));
	}
	
	public static String getMD5(byte[] source) throws NoSuchAlgorithmException 
	{
	    MessageDigest md = MessageDigest.getInstance("MD5");
	    
	    return dumpBytes(md.digest(source));
	}
	
	public static byte[] getMD5byte(byte[] source) throws NoSuchAlgorithmException 
	{
	    MessageDigest md = MessageDigest.getInstance("MD5");
	    
	    return md.digest(source);
	}
	
	private static String dumpBytes(byte[] bytes)
	{
	    StringBuilder sb = new StringBuilder(32);
	    String s = null;
	    
	    for (int i = 0; i < bytes.length; i++) {
	      	if (i % 32 == 0 && i != 0) {
	        	sb.append("\n");
	      	}
	      	s = Integer.toHexString(bytes[i]);
	      	if (s.length() < 2) {
	        	s = "0" + s;
	      	}
	      	if (s.length() > 2) {
	        	s = s.substring(s.length() - 2);
	      	}
	      	sb.append(s);
	    }
	    return sb.toString();
	}
	
	public static final String randomString(int length)
	{
        if (length < 1) {
            return null;
        }
        
        if (randGen == null) {
            synchronized (initLock) {
                if (randGen == null) {
                    randGen = new Random();
                    numbersAndLetters = ("0123456789)@!~>abcdefghijklmnopqrstuvwxyz^-=0123456789%#$ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray();
                }
            }
        }
        char [] randBuffer = new char[length];
        for (int i=0; i<randBuffer.length; i++) {
            randBuffer[i] = numbersAndLetters[randGen.nextInt(71)];
        }
        
        return new String(randBuffer);
	}
	
	public static String getRandomMD5() throws NoSuchAlgorithmException
	{
		Random random 	= new Random();
		int number  	= random.nextInt(1000000);
		
		return getMD5(new Integer(number).toString());
	}
}